import logging
from typing import Dict, Any, Optional, Callable, TypeVar

# 导入统一的日志配置模块
from log_config import setup_logging

# 配置日志
setup_logging()
logger = logging.getLogger(__name__)

T = TypeVar('T')


class DependencyContainer:
    """
    依赖注入容器
    用于管理应用程序中所有服务的生命周期和依赖关系
    支持依赖注入，便于测试时替换真实依赖
    """
    def __init__(self):
        """初始化依赖注入容器"""
        self._services: Dict[str, Any] = {}
        self._factories: Dict[str, Callable[[], Any]] = {}
        self._initialized = False
        
    def register(self, name: str, instance: Any) -> None:
        """
        注册一个服务实例
        
        Args:
            name: 服务名称
            instance: 服务实例
        """
        self._services[name] = instance
        logger.debug(f"已注册服务实例: {name}")
        
    def register_factory(self, name: str, factory: Callable[[], Any]) -> None:
        """
        注册一个服务工厂函数
        
        Args:
            name: 服务名称
            factory: 创建服务实例的工厂函数
        """
        self._factories[name] = factory
        logger.debug(f"已注册服务工厂: {name}")
        
    def get(self, name: str) -> Any:
        """
        获取指定名称的服务实例，如果服务尚未创建，则使用工厂函数创建
        
        Args:
            name: 服务名称
            
        Returns:
            服务实例
            
        Raises:
            KeyError: 当请求的服务不存在时
        """
        # 如果服务已经存在，直接返回
        if name in self._services:
            return self._services[name]
            
        # 如果有工厂函数但服务尚未创建，创建服务
        if name in self._factories:
            logger.debug(f"通过工厂函数创建服务: {name}")
            instance = self._factories[name]()
            self._services[name] = instance
            return instance
            
        # 如果服务不存在且没有工厂函数，抛出异常
        raise KeyError(f"服务 '{name}' 不存在")
        
    def initialize(self) -> None:
        """
        初始化所有服务
        按照依赖关系的顺序创建服务
        """
        if self._initialized:
            logger.warning("依赖容器已经初始化")
            return
            
        logger.info("开始初始化依赖注入容器")
        
        # 这里可以按照依赖关系的顺序初始化服务
        # 实际的初始化逻辑应该在应用启动时配置
        
        self._initialized = True
        logger.info("依赖注入容器初始化完成")
        
    def shutdown(self) -> None:
        """
        关闭所有服务，释放资源
        """
        logger.info("开始关闭依赖注入容器")
        
        # 清空服务字典，但保留工厂函数，以便容器可以重新初始化
        self._services.clear()
        self._initialized = False
        
        logger.info("依赖注入容器已关闭")
        
    def reset(self) -> None:
        """
        重置容器，清空所有服务和工厂函数
        """
        self._services.clear()
        self._factories.clear()
        self._initialized = False
        logger.info("依赖注入容器已重置")


# 创建一个默认的依赖注入容器实例，
# 方便在应用程序中使用，但不会强制要求使用单例
container = DependencyContainer()


def get_container() -> DependencyContainer:
    """
    获取默认的依赖注入容器实例
    
    Returns:
        默认的依赖注入容器实例
    """
    return container


def register_services(container: Optional[DependencyContainer] = None) -> DependencyContainer:
    """
    注册所有应用程序服务到依赖注入容器
    
    Args:
        container: 可选的依赖注入容器实例，如果不提供则使用默认容器
        
    Returns:
        配置好的依赖注入容器实例
    """
    if container is None:
        container = get_container()
        
    # 导入服务类
    from services.config_service import ConfigService
    from utils.thread_pool_manager import thread_pool_manager
    from category import CategoryManager
    from html_parser import HTMLProcessor
    from embedding import EmbeddingService
    
    # 注册配置服务工厂
    container.register_factory('config_service', ConfigService.get_instance)
    
    # 注册线程池工厂
    def create_thread_pool():
        thread_pool_manager.initialize()
        return thread_pool_manager.get_thread_pool()
    container.register_factory('thread_pool', create_thread_pool)
    
    # 注册分类管理器工厂
    def create_category_manager():
        config_service = container.get('config_service')
        category_config = config_service.get_category_config()
        return CategoryManager(
            category_dir=category_config['category_dir'],
            category_file=category_config['category_file']
        )
    container.register_factory('category_manager', create_category_manager)
    
    # 注册HTML处理器工厂
    container.register_factory('html_processor', HTMLProcessor)
    
    # 注册嵌入服务工厂
    def create_embedding_service():
        # 获取依赖的服务
        config_service = container.get('config_service')
        category_manager = container.get('category_manager')
        html_processor = container.get('html_processor')
        
        # 获取配置
        embedding_config = config_service.get_embedding_config()
        rerank_config = config_service.get_rerank_config()
        backend_config = config_service.get_backend_config()
        milvus_config = config_service.get_milvus_config()
        saved_images_config = config_service.get_saved_images_config()
        
        # 提取配置值
        embedding_model_name = embedding_config['model_name']
        embedding_model_path = embedding_config['model_path']
        rerank_model_name = rerank_config['model_name']
        rerank_model_path = rerank_config['model_path']
        backend_name = backend_config['name']
        saved_images_dir = saved_images_config['saved_images_dir']
        
        logger.info(f"嵌入模型: {embedding_model_name}, {embedding_model_path}")
        logger.info(f"重排序模型: {rerank_model_name}, {rerank_model_path}")
        logger.info(f"backend_name: {backend_name}")
        logger.info(f"saved_image_dir: {saved_images_dir}")
        
        # 创建并返回嵌入服务
        try:
            return EmbeddingService(
                category_manager=category_manager,
                html_parser=html_processor,
                embedding_model_name=embedding_model_name,
                embedding_model_path=embedding_model_path,
                rerank_model_name=rerank_model_name,
                rerank_model_path=rerank_model_path,
                milvus_connection_args=milvus_config,
                backend_name=backend_name,
                saved_images_dir=saved_images_dir
            )
        except Exception as e:
            logger.error('-------- ERROR --------')
            logger.error(f"初始化嵌入服务失败: {str(e)}")
            logger.error("如果您看到向量维度不匹配的错误，请使用以下命令删除不匹配的Milvus集合:")
            logger.error("  python milvus_manager.py list              - 列出所有集合")
            logger.error("  python milvus_manager.py delete <collection_name> - 删除特定集合")
            logger.error("  或使用: python milvus_manager.py delete-all  - 删除所有集合")
            logger.error("删除集合后请重新启动服务，系统将使用正确的维度创建新集合")
            raise
    
    container.register_factory('embedding_service', create_embedding_service)
    
    return container


def shutdown_container(container: Optional[DependencyContainer] = None) -> None:
    """
    关闭依赖注入容器中的所有服务
    
    Args:
        container: 可选的依赖注入容器实例，如果不提供则使用默认容器
    """
    if container is None:
        container = get_container()
        
    logger.info("开始关闭依赖注入容器中的服务")
    
    # 按照依赖关系的逆序关闭服务
    try:
        embedding_service = container.get('embedding_service')
        embedding_service.close()
        logger.debug("嵌入服务已关闭")
    except KeyError:
        logger.debug("嵌入服务未初始化")
    except Exception as e:
        logger.error(f"关闭嵌入服务时出错: {str(e)}")
        
    # 使用线程池管理器关闭线程池
    try:
        from utils.thread_pool_manager import thread_pool_manager
        thread_pool_manager.shutdown(wait=True)
        logger.debug("线程池已通过管理器关闭")
    except Exception as e:
        logger.error(f"通过管理器关闭线程池时出错: {str(e)}")
        
    # 关闭容器
    container.shutdown()
    logger.info("依赖注入容器中的服务已关闭")